package com.mademoisellegeek.carrentalsimulation;

import com.mademoisellegeek.carrentalsimulation.comparator.ShortestTravelComparator;
import com.mademoisellegeek.carrentalsimulation.comparator.EndDayComparator;
import com.mademoisellegeek.carrentalsimulation.comparator.StartDayComparator;
import com.mademoisellegeek.carrentalsimulation.comparator.LongestTravelComparator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class OptimisationData {

    ArrayList<Travel> requestList;
    ArrayList<Travel> failedRequests;
    ArrayList<Travel> additionalTravels;
    Map<Integer, Garage> garageDictionary;
    Map<Integer, Vehicle> vehicleDictionary;
    Map<String, Integer> towns;
    int[][] distances;

    public OptimisationData(Map<String, Integer> towns,
            int[][] distances) {
        this.requestList = new ArrayList<Travel>();
        this.failedRequests = new ArrayList<Travel>();
        this.additionalTravels = new ArrayList<Travel>();
        this.garageDictionary = new HashMap<Integer, Garage>();
        this.vehicleDictionary = new HashMap<Integer, Vehicle>();
        this.towns = towns;
        this.distances = distances;
    }

    public OptimisationData(ArrayList<Travel> requestList,
            Map<Integer, Vehicle> vehicleDictionary,
            Map<Integer, Garage> garageDictionary,
            ArrayList<Travel> failedRequests,
            ArrayList<Travel> additionalTravels,
            Map<String, Integer> towns,
            int[][] distances) {
        this.requestList = requestList;
        this.vehicleDictionary = vehicleDictionary;
        this.garageDictionary = garageDictionary;
        this.failedRequests = failedRequests;
        this.additionalTravels = additionalTravels;
        this.towns = towns;
        this.distances = distances;
    }

    public OptimisationData(OptimisationData data) {
        this.requestList = new ArrayList<Travel>();
        this.failedRequests = new ArrayList<Travel>();
        this.additionalTravels = new ArrayList<Travel>();
        this.garageDictionary = new HashMap<Integer, Garage>();
        this.vehicleDictionary = new HashMap<Integer, Vehicle>();
        for (Travel travel : data.getRequestList()) {
            this.requestList.add((Travel) travel.clone());
        }
        for (Travel travel : data.getFailedRequests()) {
            this.failedRequests.add((Travel) travel.clone());
        }
        for (Travel travel : data.getAdditionalTravels()) {
            this.additionalTravels.add((Travel) travel.clone());
        }
        for (Integer i : data.vehicleDictionary.keySet()) {
            this.vehicleDictionary.put(i, (Vehicle) data.vehicleDictionary.get(i).clone());
        }
        for (Integer i : data.garageDictionary.keySet()) {
            this.garageDictionary.put(i, (Garage) data.garageDictionary.get(i).clone());
        }
        this.towns = data.towns;
        this.distances = data.distances;
    }
    
    /*
     * Getters and setters
     */

    public Map<Integer, Vehicle> getVehicleDictionary() {
        return this.vehicleDictionary;
    }

    public ArrayList<Travel> getRequestList() {
        return this.requestList;
    }

    public Map<Integer, Garage> getGarageDictionary() {
        return this.garageDictionary;
    }

    public Garage getGarage(int garageId) {
        return this.garageDictionary.get(garageId);
    }

    public ArrayList<Travel> getFailedRequests() {
        return this.failedRequests;
    }

    public ArrayList<Travel> getAdditionalTravels() {
        return this.additionalTravels;
    }

    public int getTown(String town) {
        return this.towns.get(town);
    }

    public void setRequestList(ArrayList<Travel> requestList) {
        this.requestList = requestList;
    }
    
    /*
     * Adders
     */

    public void addGarage(int garageId, Garage garage) {
        this.garageDictionary.put(garageId, garage);
    }

    public void addVehicle(int vehicleId, Vehicle vehicle) {
        this.vehicleDictionary.put(vehicleId, vehicle);
    }

    public void addFailedRequest(Travel request) {
        this.failedRequests.add(request);
    }

    public void addTown(String town, int townId) {
        this.towns.put(town, townId);
    }
    
    public void addAdditionalTravel(Travel travel) {
        this.additionalTravels.add(travel);
    }

    public void addDistance(int town1, int town2, int nbDaysDistance) {
        this.distances[town1][town2] = nbDaysDistance;
        this.distances[town2][town1] = nbDaysDistance;
    }
    
    /*
     * Helper functions for searching optimisation data
     */

    public int getMaxDistanceFromTown(String startTown) {
        int townId = this.towns.get(startTown);
        int[] distancesCopy = this.distances[townId - 1].clone();
        Arrays.sort(distancesCopy);
        return distancesCopy[distancesCopy.length - 1];
    }

    public ArrayList<String> getTownsAtDistance(int distance, String startTown) {
        int townId = this.towns.get(startTown);
        Map<Integer, String> reversedMap = Utils.invert(this.towns);
        ArrayList<String> result = new ArrayList<String>();
        for (int i = 0; i < this.distances.length; i++) {
            if (this.distances[townId - 1][i] == distance) {
                result.add(reversedMap.get(i));
            }
        }
        return result;
    }

    public ArrayList<Garage> getGaragesInTown(String town) {
        ArrayList<Garage> result = new ArrayList<Garage>();
        for (Garage garage : this.garageDictionary.values()) {
            if (garage.getTown().equals(town)) {
                result.add(garage);
            }
        }
        return result;
    }


    /*
     * Sorting functions
     */
    
    public void sortRequestListByEndDay() {
        Collections.sort(this.requestList, new EndDayComparator());
    }

    public void sortRequestListByStartDay() {
        Collections.sort(this.requestList, new StartDayComparator());
    }

    public void sortRequestListByLongestTravel() {
        Collections.sort(this.requestList, new LongestTravelComparator());
    }

    public void sortRequestListByShortestTravel() {
        Collections.sort(this.requestList, new ShortestTravelComparator());
    }

    /*
     * Logging function
     */
    @Override
    public String toString() {
        String result = "";
        for (Vehicle vehicle : this.vehicleDictionary.values()) {
            result += vehicle.toString() + CarRentalSimulationApp.NEWLINE;
        }
        for (Garage garage : this.garageDictionary.values()) {
            result += garage.toString() + CarRentalSimulationApp.NEWLINE;
        }
        return result;
    }
}
